package containerlogistik.implementation;

import containerlogistik.interfaces.Acceleration;
import containerlogistik.interfaces.Angle;
import containerlogistik.interfaces.Bounded3DimStack;
import containerlogistik.interfaces.BoundingBox;
import containerlogistik.interfaces.Force;
import containerlogistik.interfaces.Length;
import containerlogistik.interfaces.Level;
import containerlogistik.interfaces.Mass;
import containerlogistik.interfaces.Point;
import containerlogistik.interfaces.Power;
import containerlogistik.interfaces.Speed;
import containerlogistik.interfaces.StowageLocation;
import containerlogistik.interfaces.TimeDiff;
import containerlogistik.interfaces.Work;

public final class Values {

    // convert factors
    public static final Acceleration ACCELERATION_EARTH = AccelerationInMs2.valueOf(9.80665); // Earth acceleration constant in m/s²
    public static final double LEVEL_IN_G = 0.01;
    public static final double GRAM_IN_KG = 1000; // gram to kilo factor
    public static final double TONNE_IN_KG = 0.001; // tonne to kilo factor
    public static final double KG_IN_GRAM = 1000; // gram to kilo factor
    public static final double KG_IN_TONNE = 0.001; // tonne to kilo factor
    public static final double W_IN_KW = 0.001; // watt to kilowatt factor
    public static final double MW_IN_KW = 1000; // megawatt to kilowatt factor
    public static final double KW_IN_W = 1000; // watt to kilowatt factor
    public static final double KW_IN_MW = 0.001; // megawatt to kilowatt factor
    public static final double KMH_IN_MS = 3.6;
    public static final double MHP_IN_MS = 2.2369362920544;
    public static final double M_IN_KM = 0.001; // meter to kilometer factor
    public static final double FT_IN_M = 0.3048; // ft to meter factor
    public static final double DEG_IN_RAD = Math.PI / 180.0;
    public static final double RAD_IN_DEG = 180.0 / Math.PI;
    public static final double RADIUS_AS_CIRCUMFERENCE = 2 * Math.PI;
    
    // Zero Values
    public static final Length ZERO_LENGTH = lengthInM(0d);
    public static final TimeDiff ZERO_TIMEDIFF = timeDiffInS(0d, 0d);
    public static final Speed ZERO_SPEED = speedInMS(0d);
    public static final Level ZERO_LEVEL = levelOfPedal(0);
    public static final Mass ZERO_MASS = massInKg(0);
    public static final Acceleration ZERO_ACCELERATION = accelerationInMs2(0d);
    public static final Angle ZERO_ANGLE = angleInRad(0d);
    public static final Force ZERO_FORCE = forceInN(0d);
    public static final Power ZERO_POWER = powerInKw(0d);
    public static final Point ZERO_POINT = pointIn2d(0, 0);
    public static final Work ZERO_WORK = workInNm(0d);    
    public static final BoundingBox ZERO_BOUNDINGBOX = boundingBox(ZERO_LENGTH, ZERO_LENGTH, ZERO_LENGTH); // Empty BoundingBox
    
    // Defaults
    public static final Mass DEFAULT_ISO20FT_CONTAINER_EMPTY_MASS = massInKg(2280);
    public static final Mass DEFAULT_ISO20FT_CONTAINER_MAX_MASS = massInTonne(24);
    public static final Mass DEFAULT_EUR_PALLET_MASS = massInTonne(1); // Default loading for EUR Pallet
    public static final BoundingBox DEFAULT_EUR_PALLET_BOUNDINGBOX = boundingBox(lengthInM(1200), lengthInM(800), lengthInM(1400)); // Default Euro-Pallet
    public static final BoundingBox DEFAULT_ISO20FT_CONTAINER_BOUNDINGBOX = boundingBox(lengthInFt(12), lengthInFt(8), lengthInFt(8)); // Default ISO 20ft Container
    

    /**
     * Constructor, noninstantiable
     */
    private Values() {
    }

    // Work factories ----------------------------------------------------------    
    public static Work workInNm(double n) {
        return WorkInNm.valueOf(n);
    }

    public static Work workInJ(double n) {
        return WorkInNm.valueOf(n);
    }

    public static Work workInWs(double n) {
        return WorkInNm.valueOf(n);
    }

    // Force Factories ---------------------------------------------------------
    public static Force forceInN(double n) {
        return ForceInN.valueOf(n);
    }

    // Power Factories ---------------------------------------------------------
    public static Power powerInKw(double kw) {
        return PowerInKw.valueOf(kw);
    }

    public static Power powerInW(double w) {
        return PowerInKw.valueOf(w * W_IN_KW);
    }

    public static Power powerInMw(double mw) {
        return PowerInKw.valueOf(mw * MW_IN_KW);
    }

    // Acceleration Factories --------------------------------------------------
    public static Acceleration accelerationInMs2(double ms2) {
        return AccelerationInMs2.valueOf(ms2);
    }

    // Angle Factories ---------------------------------------------------------
    public static Angle angleInRad(double rad) {
        return AngleInRad.valueOf(rad);
    }

    public static Angle angleInDeg(double deg) {
        return AngleInRad.valueOf(deg * DEG_IN_RAD);
    }

    // Mass Factories ----------------------------------------------------------
    public static Mass massInKg(double kilo) {
        return MassInKg.valueOf(kilo);
    }

    public static Mass massInG(double gram) {
        return MassInKg.valueOf(gram * GRAM_IN_KG);
    }

    public static Mass massInTonne(double tonne) {
        return MassInKg.valueOf(tonne * TONNE_IN_KG);
    }

    // Speed Factories ---------------------------------------------------------
    public static Speed speedInMS(double meterPerS) {
        return SpeedInMS.valueOf(meterPerS);
    }

    public static Speed speedInKmH(double kmH) {
        return SpeedInMS.valueOf(kmH / KMH_IN_MS);
    }

    public static Speed speedInMpH(double mpH) {
        return SpeedInMS.valueOf(mpH / MHP_IN_MS);
    }

    // Length Factories --------------------------------------------------------
    public static Length lengthInM(double meters) {
        return LengthInM.valueOf(meters);
    }
    
    public static Length lengthInFt(double ft) {
        return LengthInM.valueOf(ft * FT_IN_M);
    }

    // TimeDiff Factories ------------------------------------------------------
    /**
     * time difference between two times in seconds
     *
     * @param begin starttime
     * @param end endtime
     * @return new time difference
     */
    public static TimeDiff timeDiffInS(double begin, double end) {
        return TimeDiffInS.valueOf(begin, end);
    }

    // Level Factory -----------------------------------------------------------
    public static Level levelOfPedal(int level) {
        return LevelOfPedal.valueOf(level);
    }

    public static Level levelOfTraction(int level) {
        return LevelOfPedal.valueOf(level);
    }

    // Point Factories ---------------------------------------------------------
    public static Point pointIn2d(int x, int y) {
        return PointIn2d.valueOf(x, y);
    }
    
    // BoundingBox Factories ---------------------------------------------------
    public static BoundingBox boundingBox(Length length, Length width, Length height) {
        return BoundingBoxImpl.valueOf(length, width, height);
    }
    
    public static Bounded3DimStack bounded3DDimStack(StowageLocation stowageLocation) {
    	return Bounded3DimStackImpl.valueOf(stowageLocation);
    }
}
